package edu.whut.mall.admin.service.impl;

import com.github.pagehelper.PageHelper;
import edu.whut.mall.admin.dto.MerchantPayInfo;
import edu.whut.mall.admin.enums.OrderStatusEnum;
import edu.whut.mall.admin.enums.PaymentStatusEnum;
import edu.whut.mall.admin.enums.ProceedsFlowDirectionEnum;
import edu.whut.mall.admin.enums.RefundStatusEnum;
import edu.whut.mall.admin.mapper.PayInfoCustomMapper;
import edu.whut.mall.admin.service.IPayInfoService;
import edu.whut.mall.admin.vo.RefundRequestVo;
import edu.whut.mall.common.api.CommonPage;
import edu.whut.mall.common.api.CommonResult;
import edu.whut.mall.common.api.ResultCode;
import edu.whut.mall.common.constant.MallConstant;
import edu.whut.mall.common.exception.MallException;
import edu.whut.mall.mapper.MerchantMapper;
import edu.whut.mall.mapper.PayInfoMapper;
import edu.whut.mall.model.Merchant;
import edu.whut.mall.model.PayInfo;
import edu.whut.mall.model.PayInfoExample;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pay.d9lab.api.model.BaseResponseModule;
import pay.d9lab.api.model.RefundRequestModel;
import pay.d9lab.api.util.Api;

import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;

/**
 * @author Wayne
 * @projectName d9lab-mall
 * @description: 支付服务接口实现
 * @date 2020/11/30 19:27
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PayInfoServiceImpl implements IPayInfoService {

    private final PayInfoMapper payInfoMapper;

    private final MerchantMapper merchantMapper;

    private final PayInfoCustomMapper payInfoCustomMapper;

    @Override
    @Transactional
    public CommonResult refundProcessing(String orderNo) throws NoSuchAlgorithmException {
        CommonResult wxResult = refund(orderNo);
        if (ResultCode.SUCCESS.getCode() == wxResult.getCode()) {
            //更新退款请求
            payInfoCustomMapper.updateRefundRequestStatusByOrderNo(orderNo, RefundStatusEnum.ACCEPT_REFUND.getCode());
            //更新订单状态
            payInfoCustomMapper.updateOrderStatusByOrderNo(orderNo, OrderStatusEnum.REFUNDED.getCode());
            //更新支付状态
            payInfoCustomMapper.updatePayInfoStatusByOrderNo(orderNo, PaymentStatusEnum.REFUNDED.getCode());
            return CommonResult.success("退款成功");
        }
        return CommonResult.success("退款失败");
    }

    @Override
    public CommonPage<RefundRequestVo> listRefundRequestVoByStatus(Integer pageNum, Integer size, Integer status) {
        PageHelper.startPage(pageNum, size);
        List<RefundRequestVo> refundRequestVoList = payInfoCustomMapper.listRefundRequestVoByStatus(status);
        return CommonPage.restPage(refundRequestVoList);
    }

    @Override
    public Integer refuseRefund(String orderNo) {
        //更新订单状态
        payInfoCustomMapper.updateOrderStatusByOrderNo(orderNo, OrderStatusEnum.REJECT_REFUND.getCode());
        //更新支付状态
        payInfoCustomMapper.updatePayInfoStatusByOrderNo(orderNo, PaymentStatusEnum.REJECT_REFUND.getCode());
        //更新退款请求
        return payInfoCustomMapper.updateRefundRequestStatusByOrderNo(orderNo, RefundStatusEnum.REJECT_REFUND.getCode());
    }


    public PayInfo queryPayInfoByOrderNo(String orderNo) {
        PayInfoExample payInfoExample = new PayInfoExample();
        payInfoExample.createCriteria().andOrderNoEqualTo(orderNo);
        List<PayInfo> payInfos = payInfoMapper.selectByExample(payInfoExample);
        return org.apache.shiro.util.CollectionUtils.isEmpty(payInfos)? null : payInfos.get(0);
    }

    /**
     * 根据商户id和金钱流向来决定platformId和platformKey
     * @param merchantId
     * @param direction
     * @return
     */
    private MerchantPayInfo getMerchantPayInfoByMerchantIdAndProcessDirection(Long merchantId, Integer direction) {
        MerchantPayInfo merchantPayInfo = new MerchantPayInfo();
        String platformId, platformKey;
        Merchant merchant = merchantMapper.selectByPrimaryKey(merchantId);
        Integer currentDirection;
        if (direction == null) {
            currentDirection = merchant.getProceedsFlowDirection();
        } else {
            currentDirection = direction;
        }
        if (ProceedsFlowDirectionEnum.COMMON.getCode().equals(currentDirection)) {
            platformId = MallConstant.DEFAULT_PLATFORM_ID;
            platformKey = MallConstant.DEFAULT_PLATFORM_KEY;
        } else {
            platformId = merchant.getMerchantWxpayAccount();
            platformKey = merchant.getCompanyKey();
            if (StringUtils.isBlank(platformId) || StringUtils.isBlank(platformKey)) {
                log.error("商家id:{} 选择了独家支付但是没有appId", merchant.getId());
                throw new MallException("商家选择了独家支付但是没有appId");
            }
        }
        merchantPayInfo.setPlatformId(platformId);
        merchantPayInfo.setPlatformKey(platformKey);
        merchantPayInfo.setProceedsFlowDirection(currentDirection);
        return merchantPayInfo;
    }

    @Override
    public CommonResult refund(String orderNo) throws NoSuchAlgorithmException {
        log.info("####################开始退款#####################");
        PayInfo payInfo = queryPayInfoByOrderNo(orderNo);
        MerchantPayInfo merchantPayInfo = getMerchantPayInfoByMerchantIdAndProcessDirection(payInfo.getMerchantId(), payInfo.getProceedsFlowDirection());
        //封装参数
        Map<String,Object> map = new RefundRequestModel()
                .platform_id(merchantPayInfo.getPlatformId())
                .out_trade_no(orderNo)
                .platform_out_trade_no(payInfo.getPlatformNumber())
                .refund_amount(payInfo.getAmount().toString())
                .creatSign(merchantPayInfo.getPlatformKey());
        //生成随机字符串并加签
        //请求
        String response = Api.refund(map);
        //接参
        BaseResponseModule responseModule = new BaseResponseModule(response);
        //获取结果键值对
        Map<String,Object> valueMap = responseModule.getValueMap();
        if ((boolean)(valueMap.get("success"))) {
            log.info("退款结果{}", valueMap);
            log.info("####################退款结束---成功#####################");
            return CommonResult.success(valueMap);
        } else {
            log.info("####################退款结束---失败#####################{}", (String)valueMap.get("message"));
            log.info("失败原因：{}", valueMap.get("message"));
            log.info("####################退款结束#####################");
            return CommonResult.failed((String)(valueMap.get("message")));
        }

    }


}
